home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / System / Sample 2.4 Think C distribution / abou.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-10  |  18.7 KB  |  643 lines  |  [TEXT/KAHL]

  1. /*______________________________________________________________________
  2.  
  3.     abou.c - About Window Manager.
  4.     
  5.     Copyright © 1988, 1989, 1990 Northwestern University.  Permission is 
  6.     granted to use this code in your own projects, provided you give credit 
  7.     to both John Norstad and Northwestern University in your about box or 
  8.     document.
  9. _____________________________________________________________________*/
  10.  
  11. #include    <string.h>
  12. #include <SoundMgr.h>
  13.  
  14. #include "utl.h"
  15. #include "rez.h"
  16. #include "glob.h"
  17. #include "wstm.h"
  18. #include "abou.h"
  19. #include "help.h"
  20.  
  21. #define nil 0
  22.  
  23. /*______________________________________________________________________
  24.  
  25.     Constant Definitions.
  26. _____________________________________________________________________*/
  27.  
  28.  
  29. /* Movie states. */
  30.  
  31. typedef enum StateType {
  32.     start,                /* start the movie */
  33.     startNameLeft,        /* start sliding virus name left */
  34.     slideNameLeft,        /* slide virus name left */
  35.     slideNamesUp,        /* slide virus names up */
  36.     slideFootDown,        /* slide foot down */
  37.     slideFootUp            /* slide foot up */
  38. } StateType;
  39.  
  40. /* Timing constants, in ticks and pixels. */
  41.  
  42. #define initWait                300            /* initial wait */
  43. #define deltaNameHScroll    2                /* amount to scroll name left each
  44.                                                         time */
  45. #define deltaNameHTicks        1                /* wait between name scrolls left */
  46. #define deltaNameVScroll    2                /* amount to scroll names up each
  47.                                                         time */
  48. #define deltaNameVTicks        1                /* wait between name scrolls up */
  49. #define footWait                120            /* wait before foot starts coming down */
  50. #define deltaFootVScroll    8                /* amount to scroll foot each time */
  51. #define deltaFootVTicks        1                /* wait between foot scrolls */
  52. #define deltaSquishVTicks  2                /* wait between foot scrolls during
  53.                                                         squishing */
  54.  
  55. /*______________________________________________________________________
  56.  
  57.     Global Variables.
  58. _____________________________________________________________________*/
  59.  
  60.  
  61. static WindowPtr        AbouWindow = nil;    /* ptr to about window */
  62. static WindowRecord    AbouWRecord;        /* about window record */
  63. static WindowObject    AbouWindObject;    /* about window object */
  64. static StateType        State;                /* movie state */
  65. static long                WaitTill;            /* tick count to wait until */
  66. static RgnHandle        UpdateRgn;            /* update region for ScrollRect calls */
  67. static BitMap            FootMap;                /* offscreen foot bitmap */
  68. static GrafPort        NamePort;            /* grafPort for drawing virus names 
  69.                                                         offscreen */
  70. static BitMap            NameMap;                /* offscreen virus names bitmap */
  71. static short            MaxNameWidth;        /* max virus name width */
  72. static short            NamesLeft;            /* left coord of virus names */
  73. static Rect                NamesRect;            /* rectangle enclosing names in NameMap */
  74. static Rect                SquishRect;            /* squished names rectangle */
  75. static Rect                FootCopyRect;        /* rectangle in foot bit map to be copied */
  76. static Rect                AbouCopyRect;        /* rectangle in window to copy
  77.                                                         part of foot to */
  78. static Handle            Tune;                    /* Sousa march 'TUNE' resource handle */
  79. static Handle            Instrument;            /* 'snd ' instrument handle for Sousa march */
  80. static Handle            Splat;                /* handle to splat 'snd ' */
  81. static SndChannelPtr    MarchChan;            /* sound channel pointer for march */
  82. static SndChannelPtr    SplatChan;            /* sound channel pointer for splat */
  83. static short            *PTune;                /* pointer to next command in tune */
  84. static short            *PTuneEnd;            /* pointer to end of command in tune */
  85. static Boolean            HaveSound;            /* true if we have the Sound Manager */
  86.  
  87. /*______________________________________________________________________
  88.  
  89.     abou_IsOpen - Check to See if About Window is Open.
  90.     
  91.     Exit:        function result = true if window open.
  92. _____________________________________________________________________*/
  93.  
  94.  
  95. Boolean abou_IsOpen (void)
  96.  
  97. {
  98.     return AbouWindow != nil;
  99. }
  100.  
  101. /*______________________________________________________________________
  102.  
  103.     Update - Process an Update Event.
  104. _____________________________________________________________________*/
  105.  
  106.  
  107. static void Update (void)
  108.  
  109. {
  110.     PicHandle        mePict;                /* handle to my picture */
  111.     Handle            credits;                /* handle to credits STR# rsrc */
  112.     char                creditsStr[600];    /* credits string */
  113.     char                *pCreditsStr;        /* pointer into credits string */
  114.     char                *pCreditsRsrc;        /* pointer into credits STR# rsrc */
  115.     short                nCreditsStr;        /* number of strings in credits rsrc */
  116.     short                strLen;                /* length of credit string in rsrc */
  117.     
  118.     /* Draw my picture. */
  119.     
  120.     mePict = GetPicture(mePictID);
  121.     HLock((Handle)mePict);
  122.     DrawPicture(mePict, &RectList[meRect]);
  123.     HUnlock((Handle)mePict);
  124.     
  125.     /* Draw the credits. */
  126.     
  127.     credits = GetResource('STR#', abouCreditsID);
  128.     MoveHHi(credits);
  129.     HLock(credits);
  130.     pCreditsStr = creditsStr;
  131.     nCreditsStr = **(short**)credits;
  132.     pCreditsRsrc = *credits+2;
  133.     while (nCreditsStr--) {
  134.         strLen = *pCreditsRsrc++;
  135.         memcpy(pCreditsStr, pCreditsRsrc, strLen);
  136.         pCreditsStr += strLen;
  137.         pCreditsRsrc += strLen;
  138.     };
  139.     HUnlock(credits);
  140.     TextFont(applFont);
  141.     TextSize(9);
  142.     TextBox(creditsStr, pCreditsStr-creditsStr, 
  143.         &RectList[creditsRect], teJustLeft);
  144.     TextFont(systemFont);
  145.     TextSize(0);
  146.         
  147.     /* Draw the movie in its current state. */
  148.     
  149.     if (State == slideNameLeft || State == slideNamesUp) {
  150.         CopyBits(&NameMap, &AbouWindow->portBits, &NameMap.bounds,
  151.             &NameMap.bounds, srcCopy, nil);
  152.     } else if (State == slideFootDown || State == slideFootUp) {
  153.         if (State == slideFootDown) 
  154.             CopyBits(&NameMap, &AbouWindow->portBits, &NamesRect,
  155.                 &SquishRect, srcCopy, nil);
  156.         CopyBits(&FootMap, &AbouWindow->portBits, &FootCopyRect,
  157.             &AbouCopyRect, srcCopy, nil);
  158.     };
  159. }
  160.  
  161. /*______________________________________________________________________
  162.  
  163.     Suspend - Process a Suspend Event.
  164. _____________________________________________________________________*/
  165.  
  166.  
  167. static void Suspend (void)
  168.  
  169. {
  170.     if (MarchChan) {
  171.         SndDisposeChannel(MarchChan, true);
  172.         MarchChan = nil;
  173.     };
  174.     if (SplatChan) {
  175.         SndDisposeChannel(SplatChan, true);
  176.         SplatChan = nil;
  177.     };
  178. }
  179.  
  180. /*______________________________________________________________________
  181.  
  182.     Help - Process Mouse Down Event in Help Mode.
  183.     
  184.     Entry:        where = mouse down location, local coords.
  185. _____________________________________________________________________*/
  186.  
  187.  
  188. static void Help (Point where)
  189.  
  190. {
  191.     help_Open(tagAbouWind);
  192. }
  193.     
  194. /*______________________________________________________________________
  195.  
  196.     Close - Close the Window.
  197. _____________________________________________________________________*/
  198.  
  199.  
  200. static void Close (void)
  201.  
  202. {
  203.     if (HaveSound) {
  204.         if (MarchChan) {
  205.             SndDisposeChannel(MarchChan, true);
  206.             MarchChan = nil;
  207.         };
  208.         if (SplatChan) {
  209.             SndDisposeChannel(SplatChan, true);
  210.             SplatChan = nil;
  211.         };
  212.         HUnlock(Tune);
  213.         HUnlock(Instrument);
  214.         HUnlock(Splat);
  215.     };
  216.     Prefs.abouState.moved = AbouWindObject.moved;
  217.     wstm_Save(AbouWindow, &Prefs.abouState);
  218.     DisposeRgn(UpdateRgn);
  219.     DisposPtr(FootMap.baseAddr);
  220.     ClosePort(&NamePort);
  221.     DisposPtr(NameMap.baseAddr);
  222.     CloseWindow(AbouWindow);
  223.     AbouWindow = nil;
  224. };
  225.     
  226. /*______________________________________________________________________
  227.  
  228.     Adjust - Adjust Menus.
  229. _____________________________________________________________________*/
  230.  
  231.  
  232. static void Adjust (void)
  233.  
  234. {
  235.     MenuHandle                fileM;                    /* handle to file menu */
  236.     MenuHandle                editM;                    /* handle to edit menu */
  237.     MenuHandle                scanM;                    /* handle to scan menu */
  238.     
  239.     fileM = GetMHandle(fileMID);
  240.     editM = GetMHandle(editMID);
  241.     scanM = GetMHandle(scanMID);
  242.     EnableItem(fileM, closeCommand);
  243.     DisableItem(fileM, saveAsCommand);
  244.     DisableItem(fileM, pageSetupCommand);
  245.     DisableItem(fileM, printCommand);
  246.     DisableItem(fileM, printOneCommand);
  247.     DisableItem(editM, 0);
  248.     if (Scanning) {
  249.         DisableItem(scanM, 0);
  250.     } else {
  251.         EnableItem(scanM, 0);
  252.     };
  253. }
  254.     
  255. /*______________________________________________________________________
  256.  
  257.     PlayTune - Play the Sousa March.
  258. _____________________________________________________________________*/
  259.  
  260.  
  261. static void PlayTune (void)
  262.  
  263. {
  264.     SndCommand            cmd;                /* sound command */
  265.     static short        duration[6] = {36, 285, 570, 855, 1140, 1710};
  266.                                                 /* table of note durations */
  267.  
  268.     while (PTune < PTuneEnd) {
  269.         cmd.cmd = *PTune < 0 ? restCmd : noteCmd;
  270.         cmd.param1 = duration[((*PTune)>>8)&0x3F];
  271.         cmd.param2 = 0xFF000000 | (*PTune & 0xFF);
  272.         if (SndDoCommand(MarchChan, &cmd, true)) break;
  273.         PTune++;
  274.     };
  275. }
  276.     
  277. /*______________________________________________________________________
  278.  
  279.     Periodic - Perform Periodic Tasks.
  280. _____________________________________________________________________*/
  281.  
  282.  
  283. static void Periodic (void)
  284.  
  285. {
  286.     /* Static local variables.  These variables retain their values across
  287.         calls to this routine. */
  288.         
  289.     static short        windRight;        /* right coord of window */
  290.     static short        indVir;            /* index into virus info array */
  291.     static Str255        vName;            /* virus name */
  292.     static short        nameWidth;        /* width of virus name */
  293.     static short        stopAt;            /* coord to stop sliding at */
  294.     static Rect            scrollRect;        /* scrolling rectangle */
  295.     static short        footHeight;        /* height of foot */
  296.     static short        deltaSquish;    /* amount to expand squish rect each time */
  297.     static short        squishStart;    /* coord to start squishing */
  298.     static short        extraSquishStart;    /* coord to start squishing extra pixel */
  299.     static short        numNames;        /* number of names currently scrolled into
  300.                                                     view */
  301.     static Rect            eraseRect;        /* rectangle to be erased */
  302.     static short        namesTop;        /* top coord of NamesMap */
  303.     
  304.     /* Non-static local variables. */
  305.     
  306.     long                    ticks;            /* current tick count */
  307.     short                    extraWidth;        /* foot width minus virus names width */
  308.     short                    squishSteps;    /* number of squishing scrolls */
  309.     short                    extraSquish;    /* number of extra squishing pixels */
  310.     SndCommand            cmd;                /* sound command */
  311.     short                    noteCount;        /* number of notes in tune */
  312.         
  313.     ticks = TickCount();
  314.     if (ticks < WaitTill) return;
  315.     
  316.     /* Keep the tune going. */
  317.     
  318.     if (MarchChan) {
  319.         PlayTune();
  320.     };
  321.     
  322.     switch (State) {
  323.     
  324.         case start:
  325.             
  326.             indVir = 1;
  327.             numNames = 0;
  328.             GetIndString(vName, abouVNamesID, indVir++);
  329.             windRight = AbouWindow->portRect.right;
  330.             SetPort(&NamePort);
  331.             EraseRect(&NameMap.bounds);
  332.             SetPort(AbouWindow);
  333.             State = startNameLeft;
  334.             WaitTill = ticks + initWait;
  335.             break;
  336.             
  337.         case startNameLeft:
  338.         
  339.             nameWidth = StringWidth(vName);
  340.             scrollRect.left = windRight-deltaNameHScroll;
  341.             scrollRect.right = windRight;
  342.             scrollRect.top = AbouWindow->portRect.bottom-40;
  343.             scrollRect.bottom = scrollRect.top+16;
  344.             stopAt = NamesLeft;
  345.             namesTop = NameMap.bounds.top;
  346.             State = slideNameLeft;
  347.             
  348.             if (!MarchChan && HaveSound && InForeground) {
  349.             
  350.                 /* Allocate sound channel. */
  351.                 
  352.                 SndNewChannel(&MarchChan, sampledSynth, 0, nil);
  353.                 
  354.                 /* Install the instrument. */
  355.                 
  356.                 cmd.cmd = soundCmd;
  357.                 cmd.param1 = 0;
  358.                 cmd.param2 = (long)(*Instrument+0x16);
  359.                 SndDoCommand(MarchChan, &cmd, true);
  360.                 
  361.                 /* Start playing the tune. */
  362.                 
  363.                 noteCount = **(short**)Tune;    
  364.                 PTune = (short*)(*Tune+2);
  365.                 PTuneEnd = PTune + noteCount;
  366.                 PlayTune();
  367.             };
  368.             
  369.             break;
  370.             
  371.         case slideNameLeft:
  372.         
  373.             SetPort(&NamePort);
  374.             ScrollRect(&scrollRect, -deltaNameHScroll, 0, UpdateRgn);
  375.             SetOrigin(NamesLeft, namesTop);
  376.             if (scrollRect.left + nameWidth + 4 >= windRight) {
  377.                 MoveTo(scrollRect.left, scrollRect.bottom-4);
  378.                 DrawString(vName);
  379.             };
  380.             SetPort(AbouWindow);
  381.             CopyBits(&NameMap, &AbouWindow->portBits, &scrollRect,
  382.                 &scrollRect, srcCopy, nil);
  383.             if (scrollRect.left - deltaNameHScroll < stopAt) {
  384.                 numNames++;
  385.                 GetIndString(vName, abouVNamesID, indVir++);
  386.                 if (*vName) {
  387.                     scrollRect.right = scrollRect.left + MaxNameWidth;
  388.                     scrollRect.top = scrollRect.bottom - 16*numNames - 
  389.                         deltaNameVScroll;
  390.                     stopAt = scrollRect.top - 16 + deltaNameVScroll;
  391.                     WaitTill = ticks + deltaNameVTicks;
  392.                     State = slideNamesUp;
  393.                 } else {
  394.                     stopAt = AbouWindow->portRect.bottom - 24;
  395.                     SquishRect = scrollRect;
  396.                     SquishRect.right = SquishRect.left + MaxNameWidth;
  397.                     SquishRect.top = SquishRect.bottom - 16*numNames;
  398.                     extraWidth = (FootMap.bounds.right - FootMap.bounds.left -
  399.                         MaxNameWidth) >> 1;
  400.                     squishSteps = (16*numNames-2)/deltaFootVScroll + 1;
  401.                     deltaSquish = extraWidth/squishSteps;
  402.                     extraSquish = extraWidth - deltaSquish*squishSteps;
  403.                     extraSquishStart = stopAt - deltaFootVScroll*extraSquish;
  404.                     squishStart = SquishRect.top;
  405.                     footHeight = FootMap.bounds.bottom - FootMap.bounds.top;
  406.                     FootCopyRect = FootMap.bounds;
  407.                     FootCopyRect.top = FootCopyRect.bottom;
  408.                     AbouCopyRect = FootCopyRect;
  409.                     AbouCopyRect.top = AbouCopyRect.bottom = 0;
  410.                     eraseRect = AbouCopyRect;
  411.                     NamesRect = SquishRect;
  412.                     WaitTill = ticks + footWait;
  413.                     State = slideFootDown;
  414.                 };
  415.             } else {
  416.                 scrollRect.left -= deltaNameHScroll;
  417.                 if (scrollRect.left + nameWidth + 4 < windRight) 
  418.                     scrollRect.right = scrollRect.left + nameWidth + 4;
  419.                 WaitTill = ticks + deltaNameHTicks;
  420.             };
  421.             break;
  422.             
  423.         case slideNamesUp:
  424.         
  425.             SetPort(&NamePort);
  426.             ScrollRect(&scrollRect, 0, -deltaNameVScroll, UpdateRgn);
  427.             SetOrigin(NamesLeft, namesTop);
  428.             SetPort(AbouWindow);
  429.             CopyBits(&NameMap, &AbouWindow->portBits, &scrollRect,
  430.                 &scrollRect, srcCopy, nil);
  431.             WaitTill = ticks + deltaNameVTicks;
  432.             scrollRect.top -= deltaNameVScroll;
  433.             scrollRect.bottom -= deltaNameVScroll;
  434.             if (scrollRect.top < stopAt) State = startNameLeft;
  435.             break;
  436.             
  437.         case slideFootDown:
  438.         
  439.             AbouCopyRect.bottom += deltaFootVScroll;
  440.             FootCopyRect.top -= deltaFootVScroll;
  441.             if (AbouCopyRect.bottom > footHeight) {
  442.                 AbouCopyRect.top = AbouCopyRect.bottom - footHeight;
  443.                 FootCopyRect.top = 0;
  444.                 eraseRect.bottom = AbouCopyRect.top;
  445.                 eraseRect.top = eraseRect.bottom - deltaFootVScroll;
  446.                 EraseRect(&eraseRect);
  447.             };
  448.             CopyBits(&FootMap, &AbouWindow->portBits,
  449.                 &FootCopyRect, &AbouCopyRect, srcCopy, nil);
  450.             if (AbouCopyRect.bottom < stopAt) {
  451.                 if (AbouCopyRect.bottom > squishStart) {
  452.                     if (MarchChan) {
  453.                         SndDisposeChannel(MarchChan, true);
  454.                         MarchChan = nil;
  455.                         if (!SplatChan) {
  456.                             SndNewChannel(&SplatChan, 0, 0, nil);
  457.                             SndPlay(SplatChan, Splat, true);
  458.                         };
  459.                     };
  460.                     SquishRect.top = AbouCopyRect.bottom;
  461.                     CopyBits(&NameMap, &AbouWindow->portBits, 
  462.                         &NamesRect, &SquishRect, srcCopy, nil);
  463.                     SquishRect.left -= deltaSquish;
  464.                     SquishRect.right += deltaSquish;
  465.                     if (AbouCopyRect.bottom > extraSquishStart) {
  466.                         SquishRect.left -= 1;
  467.                         SquishRect.right += 1;
  468.                     };
  469.                     WaitTill = ticks + deltaSquishVTicks; 
  470.                 } else {
  471.                     WaitTill = ticks + deltaFootVTicks;
  472.                 };
  473.                 scrollRect.bottom += deltaFootVScroll;
  474.             } else {
  475.                 eraseRect = AbouCopyRect;
  476.                 eraseRect.top = eraseRect.bottom - deltaFootVScroll;
  477.                 State = slideFootUp;
  478.                 WaitTill = ticks + deltaFootVTicks;
  479.                 if (SplatChan) {
  480.                     SndDisposeChannel(SplatChan, true);
  481.                     SplatChan = nil;
  482.                 };
  483.             };
  484.             break;
  485.             
  486.         case slideFootUp:
  487.         
  488.             OffsetRect(&AbouCopyRect, 0, -deltaFootVScroll);
  489.             if (AbouCopyRect.bottom < footHeight) {
  490.                 AbouCopyRect.top = 0;
  491.                 FootCopyRect.top = footHeight - AbouCopyRect.bottom;
  492.             };
  493.             CopyBits(&FootMap, &AbouWindow->portBits,
  494.                 &FootCopyRect, &AbouCopyRect, srcCopy, nil);
  495.             EraseRect(&eraseRect);
  496.             OffsetRect(&eraseRect, 0, -deltaFootVScroll);
  497.             if (AbouCopyRect.bottom > 0) {
  498.                 WaitTill = ticks + deltaFootVTicks;
  499.             } else {
  500.                 WaitTill = ticks;
  501.                 State = start;
  502.             };
  503.             break;
  504.             
  505.     };
  506.             
  507. }
  508.     
  509. /*______________________________________________________________________
  510.  
  511.     abou_Open - Open Abou Window.
  512. _____________________________________________________________________*/
  513.  
  514.  
  515. void abou_Open (void)
  516.  
  517. {
  518.     GrafPort            footPort;            /* grafPort for drawing foot offscreen */
  519.     PicHandle        footPict;            /* handle to foot picture */
  520.     short                indVir;                /* loop index */
  521.     Str255            vName;                /* virus name */
  522.     short                nameWidth;            /* width of virus name */
  523.     short                numVNames;            /* number of virus names */
  524.     
  525.     /* If the window is already open, activate it. */
  526.     
  527.     if (AbouWindow) {
  528.         SelectWindow(AbouWindow);
  529.         return;
  530.     };
  531.     
  532.     /* Get the about window and restore its state. */
  533.     
  534.     AbouWindow = wstm_Restore(false, abouWindID, (Ptr)&AbouWRecord,
  535.         &Prefs.abouState);
  536.     SetPort(AbouWindow);
  537.     
  538.     /* Initialize the window object. */
  539.     
  540.     ((WindowPeek)AbouWindow)->refCon = (long)&AbouWindObject;
  541.     AbouWindObject.windKind = abouWind;
  542.     AbouWindObject.moved = Prefs.abouState.moved;
  543.     AbouWindObject.update = Update;
  544.     AbouWindObject.activate = nil;
  545.     AbouWindObject.deactivate = nil;
  546.     AbouWindObject.resume = nil;
  547.     AbouWindObject.suspend = Suspend;
  548.     AbouWindObject.click = nil;
  549.     AbouWindObject.help = Help;
  550.     AbouWindObject.grow = nil;
  551.     AbouWindObject.zoom = nil;
  552.     AbouWindObject.key = nil;
  553.     AbouWindObject.close = Close;
  554.     AbouWindObject.disk = nil;
  555.     AbouWindObject.save = nil;
  556.     AbouWindObject.pageSetup = nil;
  557.     AbouWindObject.print = nil;
  558.     AbouWindObject.edit = nil;
  559.     AbouWindObject.adjust = Adjust;
  560.     AbouWindObject.periodic = Periodic;
  561.     AbouWindObject.dialogPre = nil;
  562.     AbouWindObject.dialogPost = nil;
  563.     
  564.     /* Create the update region for the ScrollRect calls. */
  565.     
  566.     UpdateRgn = NewRgn();
  567.     
  568.     /* Allocate and initialize the offscreen foot bitmap. */
  569.     
  570.     FootMap.bounds = RectList[footRect];
  571.     FootMap.rowBytes = (((FootMap.bounds.right-FootMap.bounds.left+7)>>3) + 1) 
  572.         & 0xfffe;
  573.     FootMap.baseAddr = NewPtr(FootMap.rowBytes*(FootMap.bounds.bottom-
  574.         FootMap.bounds.top));
  575.     
  576.     /* Draw the foot picture in the offscreen bitmap. */
  577.     
  578.     OpenPort(&footPort);
  579.     SetPortBits(&FootMap);
  580.     footPort.portRect = RectList[footRect];
  581.     ClipRect(&footPort.portRect);
  582.     EraseRect(&footPort.portRect);
  583.     footPict = GetPicture(footPictID);
  584.     HLock((Handle)footPict);
  585.     DrawPicture(footPict, &footPort.portRect);
  586.     HUnlock((Handle)footPict);
  587.     ClosePort(&footPort);
  588.     SetPort(AbouWindow);
  589.     
  590.     /* Allocate the offscreen virus names bitmap and grafport. */
  591.     
  592.     MaxNameWidth = 0;
  593.     TextFont(systemFont);
  594.     TextSize(0);
  595.     numVNames = 0;
  596.     for (indVir = 1; ; indVir++) {
  597.         GetIndString(vName, abouVNamesID, indVir);
  598.         if (!*vName) break;
  599.         numVNames++;
  600.         nameWidth = StringWidth(vName);
  601.         if (nameWidth > MaxNameWidth) MaxNameWidth = nameWidth;
  602.     };
  603.     NamesLeft = (RectList[footRect].right + RectList[footRect].left 
  604.         - MaxNameWidth) >> 1;
  605.     SetRect(&NameMap.bounds, NamesLeft, 
  606.         AbouWindow->portRect.bottom - 24 - 16*numVNames,
  607.         AbouWindow->portRect.right,
  608.         AbouWindow->portRect.bottom - 24);
  609.     NameMap.rowBytes = (((NameMap.bounds.right-NameMap.bounds.left+7)>>3) + 1) & 
  610.         0xfffe;
  611.     NameMap.baseAddr = NewPtr(NameMap.rowBytes * 16 * numVNames);
  612.     OpenPort(&NamePort);
  613.     SetPortBits(&NameMap);
  614.     NamePort.portRect = NameMap.bounds;
  615.     ClipRect(&NamePort.portRect);
  616.     SetPort(AbouWindow);
  617.     
  618.     /* Get and lock the 'snd ' and 'TUNE' resources. */
  619.     
  620.     HaveSound = utl_HaveSound();
  621.     MarchChan = nil;
  622.     SplatChan = nil;
  623.     if (HaveSound) {
  624.         Tune = GetResource('TUNE', abouNotes);
  625.         MoveHHi(Tune);
  626.         HLock(Tune);
  627.         Instrument = GetResource('snd ', abouInstrument);
  628.         MoveHHi(Instrument);
  629.         HLock(Instrument);
  630.         Splat = GetResource('snd ', abouSplat);
  631.         MoveHHi(Splat);
  632.         HLock(Splat);
  633.     };
  634.     
  635.     /* Initialize the WaitTill and State variables. */
  636.     
  637.     WaitTill = 0;
  638.     State = start;    
  639.     
  640.     /* Show the about window. */
  641.     
  642.     ShowWindow(AbouWindow);
  643. }